#include "../TcpClient.h"
#include "../Connector.h"

namespace yhaida
{
    namespace Detail
    {
        void removeConnection(EventLoop *loop, const TcpConnectionPtr &conn)
        {
            loop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
        }
        void removeConnector(const ConnectorPtr &connector)
        {
        }
    }
}

using namespace yhaida;

TcpClient::TcpClient(EventLoop *loop, const InetAddress &serverAddr)
    : _mainEventLoop(CHECK_NOTNULL(loop)),
      _connector(new Connector(loop, serverAddr)),
      _retry(false),
      _start(false),
      _nextConnID(1)
{
    //设置_connector
    _connector->setNewConnectionCallFunction(std::bind(&TcpClient::newConnection, this, _1));
    LOG_INFO << "TcpClient::TcpClient[" << this
             << "] - connector " << get_pointer(_connector);
}
TcpClient::~TcpClient()
{
    LOG_INFO << "TcpClient::~TcpClient[" << this
             << "] - connector " << get_pointer(_connector);
    TcpConnectionPtr conn;
    bool unique = false;
    {
        MutexLockGuard guard(_mutex);
        unique = _connection.unique();
        conn = _connection;
    }
    //如果TCP存在
    if (conn)//share指针的析构函数是可以多次析构，只要多个对象拥有它
    {
        //TcpClient::removeConnection本质是一样的，都是回调了TcpConnection::connectDestroyed
        CloseCallback cb = std::bind(&Detail::removeConnection, _mainEventLoop, _1);
        _mainEventLoop->queueInLoop(
            //重新设置 _connection的setCloseCallback回调函数
            std::bind(&TcpConnection::setCloseCallback, conn, cb));//当conn开始析构的时候要更换回调函数，不需要重连了

        if (unique)
        {
            conn->forceClose();
        }
    }
    else
    {
        _connector->stop();
        _mainEventLoop->runAfter(static_cast<double>(1), std::bind(&Detail::removeConnector, _connector));
    }
}
//开始第一步
void TcpClient::connect()
{
    LOG_INFO << "TcpClient::connect[" << this << "] - connectiong to"
             << _connector->serverAddress().toHostPort();
    _start = true;
    _connector->start();
}

TcpConnectionPtr TcpClient::connection() const
{
    MutexLockGuard guard(_mutex);
    return _connection;
}
void TcpClient::disconnect()
{
    _start = false;
    {
        MutexLockGuard guard(_mutex);
        if (_connection)
        {
            _connection->shutdown();
        }
    }
}
void TcpClient::stop()
{
    _start = false;
    _connector->stop();//删除不断重连的定时器，_connector的析构交给share指针
}
//这个函数注册到_connector里面去了，当_connector连接成功就回调该函数，new TcpConnection
void TcpClient::newConnection(int sockfd)
{
    _mainEventLoop->assertInLoopThread();

    InetAddress peerAddr(sockets::getPeerAddr(sockfd));
    char buff[32];
    snprintf(buff, sizeof(buff), ":%s#%d", peerAddr.toHostPort().c_str(), _nextConnID);
    ++_nextConnID;
    std::string connName = buff;
    InetAddress localAddr(sockets::getLocalAddr(sockfd));
    TcpConnectionPtr conn(new TcpConnection(_mainEventLoop,
                                            connName,
                                            sockfd,
                                            localAddr,
                                            peerAddr));
    //用户接口
    conn->setConnectionCallback(_connectionCallback);
    conn->setMessageCallback(_messageCallback);
    conn->setWriteCompleteCallback(_writeCompleteCallback);

    //内部 当conn异常回调这个函数里面包括重连
    conn->setCloseCallback(std::bind(&TcpClient::removeConnection, this, _1));
    {
        MutexLockGuard guard(_mutex);
        _connection = conn;
    }
    conn->connectEstablished();
}

void TcpClient::removeConnection(const TcpConnectionPtr &conn)
{
    _mainEventLoop->assertInLoopThread();
    assert(_mainEventLoop == conn->getLoop());

    {
        MutexLockGuard guard(_mutex);
        assert(_connection == conn);
        _connection.reset();
    }

    _mainEventLoop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
    if (_retry && _start)
    {
        LOG_INFO << "TcpClient::connect[" << this << "] - Reconnecting to "
                 << _connector->serverAddress().toHostPort();
        _connector->restart();
    }
}